﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WSNs
{
    //定义更新FFT委托事件
    public delegate void UpdataFftEventHandler(int nodeID, float frequency, int startPoint, List<float> lfData); 
    public partial class CtlDataDrawer : UserControl 
    {
        

        private NodesData _nodesData = NodesData.GetInstance();

        #region Fields

        private AcqStructure _acqStruct;

        private UpdataFftEventHandler upDataFFT;
        private System.Timers.Timer _refreshTimer = new System.Timers.Timer(2000);

        private const int DivisionCountVer = 5; //纵坐标中每格分割数量
        private const int DivisionCountHor = 5; //横坐标中每格分割数量
        private const int MinGridSpacing = 18; //最小间隔 MinGridSpacing = 18
        private const int MarginSpacing = 1; //默认边缘空白
        private const string ScaleFormat = "f4"; //默认4位小数
        private const string IntFormat = "f4"; //只显示整数

        private const int IshortLineLength = 6;
        private string _stringFormatHor = "";
        private string _stringFormatVer = "";

        private readonly Color _colorBackcolor = Color.WhiteSmoke; //Brushes.WhiteSmoke
        private readonly Pen _penRect = new Pen(Color.Black);
        private readonly Pen _penDash = new Pen(Color.Green);  //Brushes.Gray  网格颜色
        private readonly Pen _penRectAdd = new Pen(Color.Gainsboro);
        private readonly Pen _penLine = new Pen(Color.Blue); //线条颜色
        private readonly Font _fontZuobiao = new Font("宋体", 9);
        private readonly Font _fontTitle = new Font("宋体", 9);
        private readonly Brush _brushZuobiao = Brushes.Black;
        private readonly Brush _brushFillRect = Brushes.White; //Brushes.White

        private int _iFontHeight;
        private int _iVerticalZuobiaoWidth;
        private int _iVerticalZuobiaoHeight;
        private int _iHorizontalZuobiaoWidth;
        private int _iHorizontalZuobiaoHeight;

        private int _gridVerCount;
        private int _gridHorCount;
        private float _gridHeight;
        private float _gridWidth;
        private float _gridLittleHeight;
        private float _gridLittleWidth;

        //坐标轴上的各个坐标
        private Rectangle _rectTitle;
        private PointF _pointfVerticalTitle;
        private readonly List<PointF> _pointfsVerticalZuobiao = new List<PointF>();
        private readonly List<string> _stringVerticalZuobiao = new List<string>();
        private Rectangle _rectHorizontalTitle;
        private readonly List<PointF> _pointfsHorizontalZuobiao = new List<PointF>();
        private readonly List<string> _stringHorizontalZuobiao = new List<string>();

        //图表
        private Rectangle _rectDiagram;
        //纵轴最大值最小值
        private float _diagramVerValueMax;
        private float _diagramVerValueMin;
        //横轴最大值最小值
        private int _diagramHorValueMax;
        private int _diagramHorValueMin;

        private float _horZuobiaoStart;
        private float _horZuobiaoEnd; 

        //数据
        private readonly List<float> _listFData = new List<float>();
            //存储原始数据  ?? 可替换为NodesData里的
        private readonly Dictionary<float, float> _dicF2FVer = new Dictionary<float, float>(); //存储纵坐标变换
        private readonly Dictionary<float, float> _dicF2FHor = new Dictionary<float, float>(); //存储横坐标变换

        private string _stringTitle = "测试节点1，位置1";
        private string _stringVerticalTitle = "测试纵坐标名称";
        private string _stringVerValueUnit = "unit";
        private string _stringHorizontalTitle = "_stringHorizontalTitle";
        private string _stringHorValueUnit = "s";

        //读数
        private Point _mouseDownPoint = new Point(0,0); //记录鼠标按下时的点
        private PointF _pointR = new Point(); //
        private Pen _penR = new Pen(Color.Red, 1); //画笔颜色 Color.Blue
        private Brush _brushR = Brushes.Red;
        private readonly Font _fR = new Font("Verdana", 10, FontStyle.Regular);
        private PointF _pR = new PointF(0,0); //存储要显示的点的实际坐标值
        private int _indexCount; //显示点数据的点数

        //信号强度显示
        private int _signalValue;
        private readonly List<Brush> _listSignalBrush = new List<Brush>
        {
            Brushes.Black,
            Brushes.Maroon,
            Brushes.Red,
            Brushes.DarkRed,
            Brushes.Olive,
            Brushes.ForestGreen,
            Brushes.Green
        };

        private bool _isDataReady = true;
        private bool _isMouseEnable = true;
        private bool _isRefresh = true;
        private int _refreshIndex = 0;  //显示起始点索引
        private int _showPointCount = 0;  //显示点数
        private const int PointsPerWindons = 1024; //每屏显示点数
        private float scale16Float = 1.0f/65536*2.5f;
        private float scale24Float = 1.0f/8388608*2.5f;
        private float meanFloat = 0;

        //产生鼠标事件
        private const int MOUSEEVENTF_LEFTDOWN = 0x02;
        private const int MOUSEEVENTF_LEFTUP = 0x04;
        private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
        private const int MOUSEEVENTF_RIGHTUP = 0x10;
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

        #endregion

        #region Properties

        public int NodeID
        {
            get { return _acqStruct.NodeID; }
        }

        public float Frequence
        {
            get { return _acqStruct.Frequency; }
            set { _acqStruct.Frequency = value; }
        }

        public Brush TitleBrush { get; set; }

        public int SignalValue
        {
            get { return _signalValue; }
            set { _signalValue = value < 6 ? value : 6; }
        }

        public bool IsLive { get; set; }

        public bool IsRefreshFft { get; set; }

        #endregion

        #region Initial

        /// <summary>
        /// config包含节点的全部参数配置信息
        /// </summary>
        /// <param name="config"></param>
        /// <param name="chn"></param>
        public CtlDataDrawer(AcqStructure config)
        {
            TitleBrush = Brushes.Black;
            IsLive = false;
            IsRefreshFft = false;
            InitializeComponent();
            //Application.AddMessageFilter(this);
            _refreshTimer.Elapsed += _refreshTimer_Elapsed;
            _refreshTimer.Enabled = true;
            _acqStruct = config;
            upDataFFT = new UpdataFftEventHandler(_nodesData.UpdataFft);
            SetStyle(ControlStyles.OptimizedDoubleBuffer |
                     ControlStyles.ResizeRedraw |
                     ControlStyles.AllPaintingInWmPaint |
                     ControlStyles.Opaque, true);
        }

        public void InitTitle(string title, string horName, string horUnit, string verName, string verUnit)
        {
            _stringTitle = title;
            _stringVerticalTitle = verName;
            _stringVerValueUnit = verUnit;
            _stringHorizontalTitle = horName;
            _stringHorValueUnit = horUnit;
        }

        #endregion

        #region Override

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            _penDash.DashStyle = DashStyle.Dash;
            this.BackColor = _colorBackcolor;
            _stringFormatVer = ScaleFormat;
            _stringFormatHor = IntFormat;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            _isRefresh = false;
            _refreshTimer.Enabled = false; //更新数据时禁止用2秒一次刷新
            if (!_isDataReady)
            {
                return;
            }
            Calculate(); //计算各绘图参数
            Draw(e.Graphics);
            if (cMenuItem_read.Text == "取消读数" && _dicF2FHor.Values.Count > 0)
            {
                ShowPoint(e.Graphics);
            }
            SetSignal(e.Graphics); //画信号指示
            
            //更新FFT数据
            if (_showPointCount > 5 && IsRefreshFft)
                upDataFFT(_acqStruct.NodeID, _acqStruct.Frequency, _refreshIndex, _listFData.GetRange(_refreshIndex, _showPointCount));
            IsRefreshFft = false;
            _isRefresh = true;
            _refreshTimer.Enabled = true;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            _mouseDownPoint = e.Location;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            #region 鼠标托动显示数据

            if (e.Button == MouseButtons.Left && _rectDiagram.Contains(_mouseDownPoint))
            {
                int indextemp = _refreshIndex;
                int i = (int) ((e.X - _mouseDownPoint.X)/((double) _rectDiagram.Width/_showPointCount));
                if (_refreshIndex - i < 0)
                {
                    _refreshIndex = 0;
                }
                else if (_refreshIndex - i >= _listFData.Count - _showPointCount)
                {
                    _refreshIndex = _listFData.Count - _showPointCount;
                }
                else
                {
                    _refreshIndex -= i;
                }
                if (indextemp != _refreshIndex)
                {
                    _mouseDownPoint = e.Location;
                }
                UpdataReadPointIndex(e);
                UpdataData();
                
            }

            #endregion

        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);

            #region 放大、缩小

            if (e.Delta > 0 && _showPointCount > 20 && _rectDiagram.Contains(e.Location)) //鼠标滚轮向上 放大
            {
                int i = (int)((double)(e.X - _rectDiagram.X) / _rectDiagram.Width * _showPointCount / 2 + _refreshIndex);
                if (i < 0)
                {
                    i = 0;
                }
                _refreshIndex = i;
                _showPointCount /= 2;
            }
            else if (e.Delta < 0 && _showPointCount > 5 && _rectDiagram.Contains(e.Location)) //鼠标滚轮向下  缩小
            {
                int i = (int)(_refreshIndex - (double)(e.X - _rectDiagram.X) / _rectDiagram.Width * _showPointCount);
                if (i < 0)
                {
                    if (_showPointCount * 2 < _listFData.Count)
                    {
                        _showPointCount *= 2;
                        i = 0;
                    }
                    else
                    {
                        _showPointCount = _listFData.Count;
                        i = 0;
                    }
                }
                else if (_showPointCount * 2 + i > _listFData.Count)
                {
                    //不做处理
                }
                else
                {
                    _showPointCount *= 2;
                }
                _refreshIndex = i;
            }

            #endregion

            OnMouseClick(e);

        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            IsRefreshFft = true;
            UpdataReadPointIndex(e); 
            UpdataData();
            
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            //return base.ProcessCmdKey(ref msg, keyData);
            if (cMenuItem_read.Text != "取消读数") return false;
            switch (keyData)
            {
                case Keys.Right:
                    if (_pR.X < _dicF2FHor.Values.Max())
                    {
                        _indexCount += 1;
                        this.Invalidate();
                    }
                    break;
                case Keys.Left:
                    if (_pR.X > _dicF2FHor.Values.Min())
                    {
                        _indexCount -= 1;
                        this.Invalidate();
                    }
                    break; 
            }
            return true;
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg >= 0x0200 && m.Msg <= 0x020A && !_isMouseEnable) return; //所有鼠标事件,刷新数据时禁用
            if (m.Msg == 0x020A) //鼠标滚轮事件,在绘图区内则放大缩小，否则可滚动绘图区
            {
                Point p = this.PointToClient(Control.MousePosition);
                if (m.WParam.ToInt64() == 7864320 && _rectDiagram.Contains(p))  //todo:32位机上可能出问题
                {
                    MouseEventArgs e = new MouseEventArgs(MouseButtons.Left, 1, p.X, p.Y, 1);
                    OnMouseWheel(e);
                }
                else if (m.WParam.ToInt64() == -7864320 && _rectDiagram.Contains(p))
                {
                    MouseEventArgs e = new MouseEventArgs(MouseButtons.Left, 1, p.X, p.Y, -1);
                    OnMouseWheel(e);
                }
                else
                    base.WndProc(ref m);
            }
            else
                base.WndProc(ref m);
        }

        #endregion

        #region Public

        /// <summary>
        /// 更新显示数据
        /// </summary>
        /// <param name="fData">要更新的数据</param>
        /// <param name="islive">是否为实时显示</param>
        public void AddaData(List<float> fData, bool islive)
        {
            _refreshTimer.Enabled = false; //更新数据时禁止用2秒一次刷新
            _isMouseEnable = false;
            IsRefreshFft = true;
            IsLive = islive;
            _listFData.AddRange(fData);
            if (!_isRefresh) return;
            _isRefresh = false;
            if (!IsLive)
            {
                _showPointCount = _listFData.Count;
                _refreshIndex = 0;
            }
            else
            {
                if (_listFData.Count > PointsPerWindons)
                {
                    _showPointCount = PointsPerWindons;
                    _refreshIndex = _listFData.Count - PointsPerWindons;
                }
                else
                {
                    _showPointCount = _listFData.Count;
                    _refreshIndex = 0;
                }
            }
            UpdataData();
        }
        /// <summary>
        /// 清除节点数据
        /// </summary>
        public void ClearData()
        {
            cMenuItem_read.Text = "读数";
            _listFData.Clear();
            _refreshIndex = 0;
            _showPointCount = 0;
            UpdataData();
        }

        /// <summary>
        /// 获取该控件的配置参数信息
        /// </summary>
        /// <returns>返回值类型为 AcqConfig</returns>
        public AcqStructure Config()
        {
            return _acqStruct;
        }

        #endregion

        #region Private

        private void _refreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            UpdataData();
            _isMouseEnable = true;
            //throw new NotImplementedException();
        }

        /// <summary>
        /// 更新数据，只需要改变_refreshIndex和_showPointCount两个参数
        /// </summary>
        private void UpdataData()
        {
            _isDataReady = false;
            try
            {
                _diagramVerValueMax = _listFData.GetRange(_refreshIndex, _showPointCount).Max();
                _diagramVerValueMin = _listFData.GetRange(_refreshIndex, _showPointCount).Min();
                _diagramHorValueMax = _refreshIndex + _showPointCount;
                _diagramHorValueMin = _refreshIndex;
            }
            catch
            {
                _diagramVerValueMax = 0;
                _diagramVerValueMin = 0;
                _diagramHorValueMax = 0;
                _diagramHorValueMin = 0;
            }
            //调整纵坐标显示，80%  1:8:1
            float span = _diagramVerValueMax - _diagramVerValueMin;
            _diagramVerValueMax = _diagramVerValueMax + span*0.03f; //0.125f    0.03f
            _diagramVerValueMin = _diagramVerValueMin - span*0.03f; //0.125f     0.03f
            _isDataReady = true;

            //refresh
            this.Invalidate();
        }

        #region 计算和绘图

        private void Calculate()
        {
            CalculateFontSize();
            CalculateDiagramRectangle();
            CalculateTitle();
            CalculateVerZuobiao();
            CalculateHorZuobiao();
            SetVerZuobiaoString();
            SetHorZuobiaoString();

            CalculateVerData();
            CalculateHorData();
            //TODO:
            //drawEndPointTextbox();
        }

        //计算字体大小
        private void CalculateFontSize()
        {
            string title = "test";
            string ver = _diagramVerValueMax.ToString(_stringFormatVer);
            string hor = _diagramHorValueMax.ToString(_stringFormatHor);
            Graphics g = this.CreateGraphics();
            //TODO:??
            SizeF sizeF = g.MeasureString(title, _fontZuobiao); //??
            _iFontHeight = Convert.ToInt32(sizeF.Height); //??

            sizeF = g.MeasureString(ver, _fontZuobiao);
            _iVerticalZuobiaoWidth = Convert.ToInt32(sizeF.Width);
            _iVerticalZuobiaoHeight = Convert.ToInt32(sizeF.Height);

            sizeF = g.MeasureString(hor, _fontZuobiao);
            _iHorizontalZuobiaoWidth = Convert.ToInt32(sizeF.Width);
            _iHorizontalZuobiaoHeight = Convert.ToInt32(sizeF.Height);

            g.Dispose();
        }

        //计算画图框的Rectangle
        private void CalculateDiagramRectangle()
        {
            int rectDiagramX = 2*MarginSpacing + _iFontHeight + _iVerticalZuobiaoWidth + IshortLineLength;
            int rectDiagramY = 2*MarginSpacing + _iFontHeight;
            int rectDiagramWidth = this.Width - rectDiagramX - MarginSpacing;
            int rectDiagramHeight = this.Height - rectDiagramY - 2*MarginSpacing - _iFontHeight -
                                    _iHorizontalZuobiaoHeight - IshortLineLength;
            if (rectDiagramWidth < 0)
            {
                rectDiagramWidth = 0;
            }
            if (rectDiagramHeight < 0)
            {
                rectDiagramHeight = 0;
            }

            _rectDiagram = new Rectangle(rectDiagramX, rectDiagramY, rectDiagramWidth, rectDiagramHeight);
        }

        //计算Title的位置
        private void CalculateTitle()
        {
            _rectTitle = new Rectangle(_rectDiagram.X, MarginSpacing, _rectDiagram.Width, _iFontHeight);
        }

        //计算纵坐标轴上各个参数的位置
        private void CalculateVerZuobiao()
        {
            _pointfsVerticalZuobiao.Clear();

            //固定分割个数：10，5，2，1
            _gridVerCount = _rectDiagram.Height/MinGridSpacing;
            if (_gridVerCount > 10)
            {
                _gridVerCount = 10;
            }
            else if (_gridVerCount > 5)
            {
                _gridVerCount = 5;
            }
            else if (_gridVerCount > 2)
            {
                _gridVerCount = 2;
            }
            else
            {
                _gridVerCount = 1;
            }
            _gridHeight = (float) _rectDiagram.Height/_gridVerCount;
            for (int i = 0; i <= _gridVerCount; i++)
            {
                _pointfsVerticalZuobiao.Add(new PointF(_rectDiagram.X - 6, _rectDiagram.Y + i*_gridHeight));
            }

            //_pointfsVerticalZuobiao.Reverse();//Y坐标应该是从大到小，与坐标名称对应

            //计算纵坐标小分格高度
            if (_gridHeight < MarginSpacing)
            {
                _gridLittleHeight = 0;
            }
            else
            {
                _gridLittleHeight = _gridHeight/DivisionCountVer;
            }

            //计算纵坐标名称绘图位置
            _pointfVerticalTitle = new PointF(
                MarginSpacing,
                _rectDiagram.Y + (_rectDiagram.Height/2.0f));
        }

        //计算横坐标轴上各个参数的位置
        private void CalculateHorZuobiao()
        {
            _pointfsHorizontalZuobiao.Clear();

            if (_iHorizontalZuobiaoWidth/2.0f > IshortLineLength)
            {
                _horZuobiaoStart = _iHorizontalZuobiaoWidth/2.0f - IshortLineLength + _rectDiagram.Left;
            }
            else
            {
                _horZuobiaoStart = _rectDiagram.Left;
            }

            if (_iHorizontalZuobiaoWidth/2.0f > MarginSpacing)
            {
                _horZuobiaoEnd = _rectDiagram.Right - _iHorizontalZuobiaoWidth/2.0f + MarginSpacing;
            }
            else
            {
                _horZuobiaoEnd = _rectDiagram.Right;
            }

            if (_iHorizontalZuobiaoWidth > MinGridSpacing)
            {
                _gridHorCount = (int) ((_horZuobiaoEnd - _horZuobiaoStart)/_iHorizontalZuobiaoWidth);
            }
            else
            {
                _gridHorCount = (int) ((_horZuobiaoEnd - _horZuobiaoStart)/MinGridSpacing);
            }

            if (_gridHorCount > 10)
            {
                _gridHorCount = 10;
            }
            else if (_gridHorCount > 5)
            {
                _gridHorCount = 5;
            }
            else if (_gridHorCount > 2)
            {
                _gridHorCount = 2;
            }
            else
            {
                _gridHorCount = 1;
            }
            _gridWidth = (_horZuobiaoEnd - _horZuobiaoStart)/_gridHorCount;

            for (int i = 0; i <= _gridHorCount; i++)
            {
                _pointfsHorizontalZuobiao.Add(new PointF(_horZuobiaoStart + i*_gridWidth, _rectDiagram.Bottom));
            }
            //计算横坐标小分格宽度
            if (_gridWidth < MarginSpacing)
            {
                _gridLittleWidth = 0;
            }
            else
            {
                _gridLittleWidth = _gridWidth/DivisionCountHor;
            }

            //计算横坐标名称绘图位置
            _rectHorizontalTitle = new Rectangle(
                _rectDiagram.X,
                this.Height - MarginSpacing*6 - _iFontHeight,
                _rectDiagram.Width,
                _iFontHeight);
        }

        //设置纵坐标轴上的各个坐标
        private void SetVerZuobiaoString()
        {
            _stringVerticalZuobiao.Clear();
            float diagramVerMaxSpan = _diagramVerValueMax - _diagramVerValueMin;
            float perValue = diagramVerMaxSpan/_gridVerCount;

            for (int i = 0; i <= _gridVerCount; i++)
            {
                string tmp = (_diagramVerValueMin + i*perValue).ToString(_stringFormatVer);
                _stringVerticalZuobiao.Add(tmp);
            }
            _stringVerticalZuobiao.Reverse();
        }

        //设置横坐标轴上的各个坐标
        private void SetHorZuobiaoString()
        {
            _stringHorizontalZuobiao.Clear();
            //todo: 当max==min时情况
            float diagramHorMaxSpan = _diagramHorValueMax - _diagramHorValueMin;
            float perValue = diagramHorMaxSpan/_gridHorCount;

            for (int i = 0; i <= _gridHorCount; i++)
            {
                string tmp = ((_diagramHorValueMin + i*perValue) / _acqStruct.Frequency).ToString(_stringFormatHor);
                _stringHorizontalZuobiao.Add(tmp);
            }
        }

        //计算纵坐标轴方向上的坐标变换
        private void CalculateVerData()
        {
            _dicF2FVer.Clear();

            float valueSpan = _diagramVerValueMax - _diagramVerValueMin;
            if (valueSpan <= 0) //最大值=最小值，为一条直线
            {
                float diagramSpan = _pointfsVerticalZuobiao.Last().Y - _pointfsVerticalZuobiao.First().Y;
                foreach (float value in _listFData.GetRange(_refreshIndex, _showPointCount).Where(value => !_dicF2FVer.ContainsKey(value)))
                {
                    _dicF2FVer.Add(value, diagramSpan/2);
                }
            }
            else
            {
                float diagramSpan = _pointfsVerticalZuobiao.Last().Y - _pointfsVerticalZuobiao.First().Y;
                foreach (float value in _listFData.GetRange(_refreshIndex, _showPointCount))
                {
                    if (_dicF2FVer.ContainsKey(value)) continue;
                    float verZuobiao = (value - _diagramVerValueMin) / valueSpan * diagramSpan;
                    _dicF2FVer.Add(value, _pointfsVerticalZuobiao.Last().Y - verZuobiao);
                }
            }
            
        }

        //计算横坐标轴方向上的坐标变换
        private void CalculateHorData()
        {
            _dicF2FHor.Clear();

            float minValue = float.Parse(_stringHorizontalZuobiao.Last()) * _acqStruct.Frequency;
            float maxValue = float.Parse(_stringHorizontalZuobiao.First()) * _acqStruct.Frequency;

            float valueSpan = maxValue - minValue;
            float diagramSpan = _pointfsHorizontalZuobiao.Last().X - _pointfsHorizontalZuobiao.First().X;
            //for (int i = 0; i < _listFData;i++ )
            for (int i = 0; i < _showPointCount; i++)
            {
                if (!_dicF2FHor.ContainsKey(i))
                {
                    float horZuobiao = (i + _refreshIndex - minValue)/valueSpan*diagramSpan;
                    _dicF2FHor.Add(i, _pointfsHorizontalZuobiao.Last().X - horZuobiao);
                }
            }
        }

        private void Draw(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.HighSpeed;
            g.Clear(this.BackColor);
            DrawRect(g);
            DrawZuobiao(g);
            //限定绘制范围为矩形框内
            g.IntersectClip(_rectDiagram);
            DrawDashLine(g);
            DrawData(g);
        }

        private void DrawRect(Graphics g)
        {
            //填充
            g.FillRectangle(_brushFillRect, _rectDiagram);
            //加粗
            g.DrawLine(_penRectAdd, _rectDiagram.X - 1, _rectDiagram.Y, _rectDiagram.X - 1, _rectDiagram.Bottom);
            g.DrawLine(_penRectAdd, _rectDiagram.X + 1, _rectDiagram.Y, _rectDiagram.X + 1, _rectDiagram.Bottom);
            g.DrawLine(_penRectAdd, _rectDiagram.X, _rectDiagram.Bottom - 1, _rectDiagram.Right, _rectDiagram.Bottom - 1);
            g.DrawLine(_penRectAdd, _rectDiagram.X, _rectDiagram.Bottom + 1, _rectDiagram.Right, _rectDiagram.Bottom + 1);
            //画矩形
            g.DrawRectangle(_penRect, _rectDiagram);
        }

        private void DrawZuobiao(Graphics g)
        {
            //Title
            StringFormat sfTitle = new StringFormat();
            sfTitle.Alignment = StringAlignment.Center;
            g.DrawString(_stringTitle, _fontTitle, TitleBrush, _rectTitle, sfTitle);
            //纵坐标轴
            string ver = _stringVerticalTitle;
            if (!string.IsNullOrEmpty(_stringVerValueUnit))
            {
                ver += "(" + _stringVerValueUnit + ")";
            }
            DrawRotatedString(ver, -90, g, _fontZuobiao, _brushZuobiao, _pointfVerticalTitle);
            //横坐标轴
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            string hor = _stringHorizontalTitle;
            if (!string.IsNullOrEmpty(_stringHorValueUnit))
            {
                hor += "(" + _stringHorValueUnit + ")";
            }
            g.DrawString(hor, _fontZuobiao, _brushZuobiao, _rectHorizontalTitle, sf);
            //纵坐标
            for (int idx = 0; idx < _pointfsVerticalZuobiao.Count; idx++)
            {
                PointF p = _pointfsVerticalZuobiao[idx];

                //坐标
                g.DrawString(
                    _stringVerticalZuobiao[idx],
                    _fontZuobiao,
                    _brushZuobiao,
                    p.X - MarginSpacing - _iVerticalZuobiaoWidth,
                    p.Y - _iVerticalZuobiaoHeight/2.0f);
            }

            //横坐标
            for (int idx = 0; idx < _pointfsHorizontalZuobiao.Count; idx++)
            {
                PointF p = _pointfsHorizontalZuobiao[idx];

                //坐标
                g.DrawString(
                    _stringHorizontalZuobiao[idx],
                    _fontZuobiao,
                    _brushZuobiao,
                    p.X - _iHorizontalZuobiaoWidth/2.0f,
                    p.Y + MarginSpacing);
            }
            if (_gridLittleWidth > 0)
            {
                if (_horZuobiaoStart > _rectDiagram.X)
                {
                    float offset = _horZuobiaoStart - _rectDiagram.X;
                    while (offset > _gridLittleWidth)
                    {
                        offset -= _gridLittleWidth;
                        g.DrawLine(_penRect,
                            _rectDiagram.X + offset, _rectDiagram.Bottom,
                            _rectDiagram.X + offset, _rectDiagram.Bottom + MarginSpacing/2.0f);
                    }
                }
                if (_horZuobiaoEnd < _rectDiagram.Right)
                {
                    float offset = _rectDiagram.Right - _horZuobiaoEnd;
                    while (offset > _gridLittleWidth)
                    {
                        offset -= _gridLittleWidth;
                        g.DrawLine(_penRect,
                            _rectDiagram.Right - offset, _rectDiagram.Bottom,
                            _rectDiagram.Right - offset, _rectDiagram.Bottom + MarginSpacing/2.0f);
                    }
                }
            }
        }

        //centrePointF指的是左边中心坐标
        public void DrawRotatedString(String text, float angle, Graphics g, Font font, Brush brush, PointF centrePointF)
        {
            SizeF labelSize = g.MeasureString(text, font);
            Bitmap stringmap = new Bitmap((int) labelSize.Height + 1, (int) labelSize.Width + 1);
            Graphics gbitmap = Graphics.FromImage(stringmap);
            gbitmap.SmoothingMode = SmoothingMode.AntiAlias;
            gbitmap.TranslateTransform(0, labelSize.Width);
            gbitmap.RotateTransform(-90);
            gbitmap.DrawString(text, font, brush, new PointF(0, 0), new StringFormat());
            //这里如果使用float坐标会导致字体不清晰，所以使用Point类型
            Point point = new Point((int) centrePointF.X, (int) (centrePointF.Y - (stringmap.Height/2.0f)));
            g.DrawImage(stringmap, point);
            //Dispose of your bitmap and graphics objects at the end
            gbitmap.Dispose();
            stringmap.Dispose();
        }

        private void DrawDashLine(Graphics g)
        {
            //虚线
            for (int i = 0; i < _pointfsVerticalZuobiao.Count; i++)
            {
                PointF p = _pointfsVerticalZuobiao[i];
                if (p.Y != _rectDiagram.Bottom && p.Y != _rectDiagram.Top)
                {
                    g.DrawLine(_penDash, p.X, p.Y, _rectDiagram.Right, p.Y);
                }
            }
            for (int i = 0; i < _pointfsHorizontalZuobiao.Count; i++)
            {
                PointF p = _pointfsHorizontalZuobiao[i];
                if (p.X != _rectDiagram.Left && p.X != _rectDiagram.Right)
                {
                    g.DrawLine(_penDash, p.X, p.Y, p.X, _rectDiagram.Top);
                }
            }
        }

        private void DrawData(Graphics g)
        {
            Point p_temp = new Point(-1000, -1000); //缓存中间变量，-1000是为了始p初始点比这个值大
            int p_temp_Ymax = -1000;
            int p_temp_Ymin = 1000000;
            bool _isfirst = true;
            if (_showPointCount < 2)
            {
                return;
            }
            for (int i = 0; i < _showPointCount; i++)
            {
                Point p = new Point((int) (_dicF2FHor[i] + 0.5), (int) (_dicF2FVer[_listFData[i + _refreshIndex]] + 0.5));
                    //四舍五入取整
                if (p.X > p_temp.X && _isfirst != true) //i为1时是第一个先进入else判断 //p.X > p_temp.X说明进入了下一个像素点
                {
                    try
                    {
                        g.DrawLine(_penLine, 20, 20, 20, 20);
                        g.DrawLine(_penLine, p_temp.X, p_temp_Ymax, p_temp.X, p_temp_Ymin);
                        g.DrawLine(_penLine, p_temp.X, p_temp.Y, p.X, p.Y);
                        p_temp = p;
                        p_temp_Ymin = p.Y;
                        p_temp_Ymax = p.Y;
                    }
                    catch
                    {
                        int i1 = 0;
                    }
                }
                else
                {
                    _isfirst = false;
                    if (p.Y > p_temp_Ymax) //记录Y最大值
                    {
                        p_temp_Ymax = p.Y;
                    }
                    if (p.Y < p_temp_Ymin) //记录Y最小值
                    {
                        p_temp_Ymin = p.Y;
                    }
                    p_temp = p; //记录最后一个p值
                }
            }
        }

        private void SetSignal(Graphics g)
        {
            g.ResetClip();
            g.IntersectClip(_rectTitle);
            SizeF titleSize = g.MeasureString(_stringTitle, _fR); //获取Title字符串的尺寸
            for (int i = 0; i < 7; i++) //设置底色
            {
                g.DrawLine(new Pen(Brushes.Silver, 2),
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 5*i, _rectTitle.Height,
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 5*i, _rectTitle.Height - i*2);
            }

            for (int i = 0; i < SignalValue + 1; i++) //画信号
            {
                g.DrawLine(new Pen(_listSignalBrush[SignalValue], 2),
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 5*i, _rectTitle.Height,
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 5*i, _rectTitle.Height - i*2);
            }
            if (SignalValue == 0) //offline
            {
                g.DrawLine(new Pen(Brushes.DarkRed, 1.7f),
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 5, _rectTitle.Height - 6,
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 11, _rectTitle.Height - 12);
                g.DrawLine(new Pen(Brushes.DarkRed, 1.7f),
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 5, _rectTitle.Height - 12,
                    _rectTitle.Width/2 + titleSize.Width/2 + 50 + 11, _rectTitle.Height - 6);
            }
        }

        #endregion

        #region 鼠标右键操作

        private void cMenuItem_read_Click(object sender, EventArgs e)
        {
            if (cMenuItem_read.Text == "读数")
            {
                cMenuItem_read.Text = "取消读数";
                DoMouseClick();
            }
            else
            {
                cMenuItem_read.Text = "读数";
                this.Invalidate();
            }
        }

        private void ShowPoint(Graphics g)
        {
            if (_indexCount > _dicF2FHor.Count - 1)
                _indexCount = _dicF2FHor.Count - 1;
            _pR = new PointF(_dicF2FHor[_indexCount], _dicF2FVer[_listFData[_indexCount + _refreshIndex]]);
            _penR.DashStyle = DashStyle.Dash;
            g.DrawLine(_penR, new PointF(_pR.X, 0), new PointF(_pR.X, Height));
            g.DrawEllipse(_penR, _pR.X - 3, _pR.Y - 3, 6, 6);
            if (_pR.X > Width - 80 && _pR.Y < Height - 60) //判断显示数据是否超出右边界，超出则显示在左边
            {
                g.DrawString("X:" + ((_indexCount + _refreshIndex) / _acqStruct.Frequency).ToString(), _fR, _brushR, _pR.X - 80, _pR.Y);
                g.DrawString("Y:" + _listFData[_indexCount + _refreshIndex].ToString(), _fR, _brushR, _pR.X - 80, _pR.Y + 10);
            }
            else if (_pR.X < Width - 80 && _pR.Y < Height - 60)
            {
                g.DrawString("X:" + ((_indexCount + _refreshIndex) / _acqStruct.Frequency).ToString(), _fR, _brushR, _pR.X + 3, _pR.Y);
                g.DrawString("Y:" + _listFData[_indexCount + _refreshIndex].ToString(), _fR, _brushR, _pR.X + 3, _pR.Y + 10);
            }
            else if (_pR.X > Width - 80 && _pR.Y > Height - 60)
            {
                g.DrawString("X:" + ((_indexCount + _refreshIndex) / _acqStruct.Frequency).ToString(), _fR, _brushR, _pR.X - 80, _pR.Y - 25);
                g.DrawString("Y:" + _listFData[_indexCount + _refreshIndex].ToString(), _fR, _brushR, _pR.X - 80, _pR.Y - 15);
            }
            else
            {
                g.DrawString("X:" + ((_indexCount + _refreshIndex) / _acqStruct.Frequency).ToString(), _fR, _brushR, _pR.X + 3, _pR.Y - 25);
                g.DrawString("Y:" + _listFData[_indexCount + _refreshIndex].ToString(), _fR, _brushR, _pR.X + 3, _pR.Y - 15);
            }
        }

        private void UpdataReadPointIndex(MouseEventArgs e)
        {
            if (cMenuItem_read.Text != "取消读数" || _dicF2FHor.Values.Count <= 0) return;
            if (!(e.X > _dicF2FHor.Values.Min()) || !(e.X < _dicF2FHor.Values.Max())) return;
            float showDataWidth = (_dicF2FHor.Values.Max() - _dicF2FHor.Values.Min())/(_showPointCount - 1);
            float readdatacount = (e.X - _dicF2FHor.Values.Min())/showDataWidth;
            _indexCount = (int) Math.Round(readdatacount);
        }

        private void cMenuItem_clear_Click(object sender, EventArgs e)
        {
            cMenuItem_read.Text = "读数";
            _listFData.Clear();
            _refreshIndex = 0;
            _showPointCount = 0;
            UpdataData();
        }

        private void cMenuItem_saveas_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "文本文件|*.txt|实验室文件|*.set";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.RestoreDirectory = true;
            string name = "N" + NodeID + "_采样率" + _acqStruct.Frequency + "Hz_" + "点数" + _listFData.Count;
            saveFileDialog.FileName = name;
            if (saveFileDialog.ShowDialog() != DialogResult.OK) return;
            FileInfo fi = new FileInfo(saveFileDialog.FileName);
            switch (fi.Extension)
            {
                case ".set":
                    FileStream fis = new FileStream(saveFileDialog.FileName, FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(fis);
                    //保存.set文件
                    bw.Write((Int32)1);                     //通道数
                    bw.Write(Convert.ToInt32(1));           //测点号
                    bw.Write(1);                            //通道号
                    bw.Write(131072);                       //采样方式及特殊通道信息
                    bw.Write(_acqStruct.Frequency);         //采样频率
                    bw.Write(_listFData.Count);             //采样长度
                    bw.Write(1);                            //未知参数
                    bw.Write((char)0);                      //bw.Write(NodeMessage); 测点信息
                    bw.Write("V");                          //工程单位
                    bw.Write("2011/11/11/11:11:11");        //时间
                    bw.Write((Single)1);                    //前端放大倍数
                    bw.Write((Single)1);                    //参数K
                    bw.Write((float)0);                     //参数B
                    bw.Write(0f);                           //抗混叠滤波
                    bw.Flush();
                    bw.Close();
                    fis.Close();

                    //保存.dat文件
                    fis = new FileStream(saveFileDialog.FileName.Replace(".set", ".dat"), FileMode.Create);
                    bw = new BinaryWriter(fis);
                    foreach (float data in _listFData)
                    {
                        bw.Write(data);
                    }
                    bw.Flush();
                    bw.Close();
                    fis.Close();
                    break;
                case ".txt":
                    StreamWriter sw = new StreamWriter(saveFileDialog.FileName, false);
                    sw.WriteLine("采样率：" + _acqStruct.Frequency + "Hz" + " , 点数：" + _listFData.Count);
                    sw.WriteLine("time:\t" + "node:" + NodeID);
                    int i = 0;
                    foreach (float data in _listFData)
                    {
                        sw.Write(((i ++) / _acqStruct.Frequency).ToString("f6") + "\t");
                        sw.WriteLine(data.ToString("f9"));
                    }
                    sw.Close();
                    break;
            }
            MessageBox.Show("转换完成！");
        }

        #endregion

        private static void DoMouseClick()
        {
            //Call the imported function with the cursor's current position
            int X = Cursor.Position.X;
            int Y = Cursor.Position.Y;
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
        }

        #endregion

    }
}
